
package ija.xls.xml.config;

import java.io.FileWriter;
import java.io.IOException;
import org.dom4j.*;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;

/**
 * Trida je zodpovedna za cteni a zapis konfigurace z/do xml souboru.
 * 
 * @author Radek Necas, xnecas18
 */
public class ConfigReaderWriter {
    
    static public String IMPLICIT_PATH = "./config/configuration.xml";
    
    protected Document docIn;
    protected Document docOut;
    
    
    /**
     * Konstruktor nastavi polozky na null.
     */
    public ConfigReaderWriter() {
        docIn = null;
        docOut = null;
    }
  
    
    ////////////////////////////////////////////////////////////////////////////
    //-------------------------- READER ---------------------------------------
    ///////////////////////////////////////////////////////////////////////////
    
    
    /**
     * Inicializuje vstup - cast reader.
     * initInput musi byt volan pred ctenim konfigurace
     * 
     * @param pathToConfig cesta ke konfiguracnimu souboru
     * @throws DocumentException 
     */
    public void initInput(String pathToConfig) throws DocumentException {
        SAXReader reader = new SAXReader();
        this.docIn = reader.read(pathToConfig);
    }
    
    /**
     * Inicializuje vstup - cast reader.
     * initInput musi byt volan pred ctenim konfigurace
     * 
     * @throws DocumentException 
     */
    public void initInput() throws DocumentException {
        SAXReader reader = new SAXReader();
        this.docIn = reader.read(IMPLICIT_PATH);
    }
    
    /**
     * @return cesta k obrazku bileho kamene
     */
    public String getPieceWhite() {
        return getStringItem("/IjaConfiguration/paths/images/pieceWhite");
    }
    
    /**
     * @return cesta k obrazku cerneho kamene
     */
    public String getPieceBlack() {
        return getStringItem("/IjaConfiguration/paths/images/pieceBlack");
    }
    
    /**
     * 
     * @return cesta k obrazku bile damy
     */
    public String getQueenWhite() {
        return getStringItem("/IjaConfiguration/paths/images/queenWhite");
    }
    
    /**
     * 
     * @return cesta k obrazku cerne damy
     */
    public String getQueenBlack() {
        return getStringItem("/IjaConfiguration/paths/images/queenBlack");
    }
    
    /**
     * 
     * @return cesta k obrazku s pozadim sachovnice
     */
    public String getBackGround() {
        return getStringItem("/IjaConfiguration/paths/images/background");
    }
    
    /**
     *
     * @return cesta ke slozce, ve ktere jsou ulozeny hry
     */
    public String getSaveGame() {
        return getStringItem("IjaConfiguration/paths/saveGame");
    }
    
    /**
     * 
     * @return cesta ke slozce, ve ktere jsou ulozeni hraci
     */
    public String getStorePlayers() {
        return getStringItem("IjaConfiguration/paths/storePlayers");
    }
    
    /**
     * 
     * @return typ notace hry
     */
    public String getNotationType() {
        return getStringItem("IjaConfiguration/notation/type");
    }
    
    
    ////////////////////////////////////////////////////////////////////////////
    //-------------------------- WRITER ---------------------------------------
    ///////////////////////////////////////////////////////////////////////////
    
    
    /**
     * Inicializuje vystupni cast - writer.
     * Musi byt volana pred pokusy o zapis.
     * Vytvari sablonu dokumentu.
     */
    public void initOutput() {
        this.docOut = DocumentHelper.createDocument();
        Element root = this.docOut.addElement("IjaConfiguration");
        
        Element paths = root.addElement("paths");
        Element imgs = paths.addElement("images");
        
        imgs.addElement("pieceWhite");
        imgs.addElement("pieceBlack");
        imgs.addElement("queenWhite");
        imgs.addElement("queenBlack");
        imgs.addElement("background");
        
        paths.addElement("saveGame");
        paths.addElement("storePlayers");
        
        Element not = root.addElement("notation");
        not.addElement("type");
    }
    
    /**
     * Nastavuje cestu k obrazku s bilym kamenem.
     * Pokud je volana vicekrat, hodnoty se prepisuji.
     * Musi pred ni byt volana nektera z funkci initOutput
     * @param path cesta k obrazku s bilym kamenem
     * @return true - OK, false - CHYBA
     */
    public boolean setPieceWhite(String path) {        
        return setStringItem("/IjaConfiguration/paths/images/pieceWhite", path);
    }
    
    /**
     * Nastavuje cestu k obrazku s cernym kamenem.
     * Pokud je volana vicekrat, hodnoty se prepisuji.
     * Musi pred ni byt volana nektera z funkci initOutput
     * @param path cesta k obrazku s cernym kamenem
     * @return true - OK, false - CHYBA
     */
    public boolean setPieceBlack(String path) {
        return setStringItem("/IjaConfiguration/paths/images/pieceBlack", path);
    }
    
    /**
     * Nastavuje cestu k obrazku s bilou damou.
     * Pokud je volana vicekrat, hodnoty se prepisuji.
     * Musi pred ni byt volana nektera z funkci initOutput
     * @param path cesta k obrazku s bilou damou
     * @return true - OK, false - CHYBA
     */
    public boolean setQueenWhite(String path) {
        return setStringItem("/IjaConfiguration/paths/images/queenWhite", path);
    }
    
    /**
     * Nastavuje cestu k obrazku s cernou damou.
     * Pokud je volana vicekrat, hodnoty se prepisuji.
     * Musi pred ni byt volana nektera z funkci initOutput
     * @param path cesta k obrazku s cernou damou
     * @return true - OK, false - CHYBA
     */
    public boolean setQueenBlack(String path) {
        return setStringItem("/IjaConfiguration/paths/images/queenBlack", path);
    }
    
    /**
     * Nastavuje cestu k obrazku s pozadim.
     * Pokud je volana vicekrat, hodnoty se prepisuji.
     * Musi pred ni byt volana nektera z funkci initOutput
     * @param path cesta k obrazku s pozadim
     * @return true - OK, false - CHYBA
     */
    public boolean setBackGround(String path) {
        return setStringItem("/IjaConfiguration/paths/images/backGround", path);
    }
    
    /**
     * Nastavuje cestu k adresari ve kterem budou ukladany ulozene hry
     * Pokud je volana vicekrat, hodnoty se prepisuji.
     * Musi pred ni byt volana nektera z funkci initOutput
     * @param path adresar ve kterem budou ukladany hry
     * @return true - OK, false - CHYBA
     */
    public boolean setSaveGame(String path) {
        return setStringItem("/IjaConfiguration/paths/saveGame", path);
    }
    
    /**
     * Nastavuje cestu k adresari ve kterem budou ukladany hraci
     * Pokud je volana vicekrat, hodnoty se prepisuji.
     * Musi pred ni byt volana nektera z funkci initOutput
     * @param path adresar ve kterem budou ukladany hraci
     * @return true - OK, false - CHYBA
     */
    public boolean setStorePlayers(String path) {
        return setStringItem("/IjaConfiguration/paths/storePlayers", path);
    }
    
    /**
     * Nastavuje typ notace.
     * Pokud je volana vicekrat, hodnoty se prepisuji.
     * Musi pred ni byt volana nektera z funkci initOutput
     * @param path adresar ve kterem budou ukladany hry
     * @return true - OK, false - CHYBA
     */
    public boolean setNotation (String notationType) {
        return setStringItem("/IjaConfiguration/notation/type", notationType);
    }
    
    
    
    /**
     * Metoda ulozi xml do souboru.
     * Pokud neni xml naplneno vytvori se soubor s korenovym adresarem.
     * @param filename nazev souboru (s cestou k nemu)
     * @throws IOException 
     */
    public void writeToFile(String filename) throws IOException {
        if (this.docOut == null) {
            this.docOut = DocumentHelper.createDocument();
            Element root = this.docOut.addElement("IjaConfiguration");
        }

        OutputFormat format = OutputFormat.createPrettyPrint();
        XMLWriter writer = new XMLWriter(new FileWriter(filename), format);
        // XMLWriter writer = new XMLWriter(System.out, format);
        writer.write(this.docOut);
        writer.flush();
        writer.close();
    }
    
    /**
     * Metoda ulozi xml do implicitniho souboru.
     * Pokud neni xml naplneno vytvori se soubor s korenovym adresarem.
     * @throws IOException 
     */
    public void writeToFile() throws IOException {
        writeToFile(IMPLICIT_PATH);
    }
    
    
    
    ////////////////////////////////////////////////////////////////////////////
    //-------------------------- SOUKROME METODY ------------------------------
    ///////////////////////////////////////////////////////////////////////////
    
    
    /**
    * Metoda nacita z xml textovou hodnotu elementu daneho xPath.
    * 
    * @param xPath
    *            cesta k elementu
    * @return textovy obsah elementu nebo null, pokud takovy element nebyl
    *         nalezen
    */
    private String getStringItem(String xPath) {
        if (this.docIn != null) {
            Node node = this.docIn.selectSingleNode(xPath);
            if (node != null) {
                return node.getText();
            }
        }

        return null;
    }
    
    
    /**
     * Metoda slouzi pro naplneni textoveho elementu
     * @param xPath cesta k elementu v xPath
     * @param value hodnota elementu
     * @return true - OK, false - CHYBA (element neexistuje, null parametry)
     */
    private boolean setStringItem(String xPath, String value) {
        if (value == null || xPath == null) {
            return false;
        }

        Element el = (Element) this.docOut.selectSingleNode(
                xPath);
        if(el == null) {
            return false;
        }

        el.addText(value);
        
        return true;
    }
}
